'use strict';
//房间模块
var roomMgr = require("./roommgr");//用户模块
var userMgr = require("./usermgr");
//数据库模块
var db = require("../utils/db");
//胡牌算法
var hupai = require("./zunyi_hupai");
//串行异步
var async = require("async");
//配置
var configPai = require("./config_tool");
//api
var _ = require("lodash");
//常量
var constant = require('../utils/constant');
var cn = require('../utils/const');

var card = require('./channel_card_type');
var channel = require('./compare_channel');

//鸡牌算分
var _Jipai = require('./jiPai');
var positionService = require("../services/positionService");
var log4js = require('log4js');
var log = log4js.getLogger("zunyiGameMgr");
var action_count = 0;
var timer = null;

/***********************全局定义******************/
//游戏数据
var games = {};
//座位数据
var gameSeatsOfUsers = {};
//解散列表
var dissolvingList = [];
//白板牌
var baibanPai = 29;
//最大牌
var maxPai = 78;

//无效牌
var INVALID_PAI = -1;
//任意牌(任意一张牌来了都胡)
var anyHuPai = INVALID_PAI;
//动作枚举
var ACTION_CHUPAI = 1;
var ACTION_MOPAI = 2;
var ACTION_PENG = 3;
var ACTION_GANG = 4;
var ACTION_HU = 5;
var ACTION_ZIMO = 6;
var ACTION_CHI = 7;

//底数
var DISHU_FIRST = [2, 4, 6, 8];
var DISHU_SECOND = [2, 2, 2, 2];

//当前房间当前局结算
var roomRes = {};

var strCoverMap = {
    0: 'jingJiScore',
    1: 'yingJiScore',
    2: 'wuJiScore',
    3: 'waJiScore'
};

//开始新的一局
exports.begin = function (roomId) {
    //房间数据
    var roomInfo = roomMgr.getRoom(roomId);
    if (roomInfo == null) {
        return;
    }
    roomRes[roomId] = null;

    var typeInfo = constant.CreateRoomInfo.type[roomInfo.conf.type];
    //游戏数据
    var game = {
        conf: roomInfo.conf,                 //房间配置
        roomInfo: roomInfo,                  //房间信息
        gameIndex: roomInfo.numOfGames,      //局数
        dishu: roomInfo.conf.dishu,          //底数类型
        button: roomInfo.nextButton,         //庄家
        cards: [],                //扑克集合
        currentIndex: 0,                     //摸牌索引
        gameSeats: new Array(typeInfo.seatlen),    //座位信息
        turn: 0,                             //轮到某某
        chuPai: -1,                          //当前出牌
        state: constant.GameStatus.IDLE,     //游戏状态
        paidun: 0,                           //牌墩
    };

    //更新房间配置信息
    var paiNum = constant.CreateRoomInfo.paiNum[game.conf.paiNum];
    if (paiNum) {  // 更新局数和局数钻石
        game.jushu = paiNum.jushu;
        game.jushucost = paiNum.jushucost;
        roomInfo.conf.maxGames = game.jushu;
    }

    //更新历史局数，分数等
    updateHistoryData(roomInfo, game);

    //初始化座位
    var seats = roomInfo.seats;
    for (var i = 0; i < typeInfo.seatlen; ++i) {
        //游戏座位数据
        var data = game.gameSeats[i] = {};
        //游戏数据
        data.game = game;
        //座位索引
        data.seatIndex = i;
        //玩家标识
        data.userId = seats[i].userId;
        //持有的牌
        data.holds = [];
        //打出的牌
        data.folds = [];
        //打出的牌被吃碰和点杠后剩余的牌
        data.lestFolds = [];
        //暗杠的牌
        data.angangs = [];
        //点杠的牌
        data.diangangs = [];
        //弯杠的牌
        data.wangangs = [];
        //碰了的牌
        data.pengs = [];
        //缺一门
        data.que = -1;
        //吃了的牌
        data.chis = [];
        //玩家手上的牌的数目，用于快速判定碰杠
        data.countMap = {};
        //玩家听牌，用于快速判定胡了的番数
        data.tingMap = {};
        // 自动出牌状态
        data.acChuPaiStatus = false;
        //是否可以出牌
        data.canChuPai = false;
        //是否胡了
        data.hued = false;
        //是否是自摸
        data.iszimo = false;
        //分数
        data.score = 0;
        //是否确认出牌
        data.isSubmit = false;
        //发牌时间
        data.beginTime = Date.now();

        //座位数据
        gameSeatsOfUsers[data.userId] = data;
    }

    //存储每局游戏数据
    games[roomId] = game;

    //加入是否测试
    TestModel(game);

    //游戏状态推送
    userMgr.broadcastInRoom('game_status_push', { state: game.state }, seats[0].userId, true);

    //开牌墩
    delayToBegin(game);
};

//更新历史数据，包括局数 历史分数等
function updateHistoryData(roomInfo, game) {
    if (!roomInfo.bcheckfinish) {
        roomInfo.numOfGames++;
        roomInfo.eachBankers.push(game.button);
    }
    else {
        db.get_shisanshui_eachround_data(roomInfo.id, function (data) {
            if (data != null) {
                for (var j = 0; j < data.length; ++j) {
                    //roomInfo.eachBankers[j] = data[j].banker_index;
                    roomInfo.conf.zhuangMode = data[j].banker_mode;
                    for (var k = 0; k < data[j].history.seats.length; ++k) {
                        //玩家每局结果
                        if (roomInfo.seats[k] === undefined || roomInfo.seats[k] == null) {
                            continue;
                        }
                        if (roomInfo.seats[k].roundScore === undefined) {
                            roomInfo.seats[k].roundScore = [];
                        }
                        if (data[j].end_time != null) {
                            roomInfo.seats[k].roundScore.push(data[j].history.seats[k].score);
                        }
                        //玩家累计结果
                        if (roomInfo.seats[k].score == null) {
                            roomInfo.seats[k].score = 0;
                        }
                        roomInfo.seats[k].score += data[j].history.seats[k].score;
                    }
                }
                //已经结束上局
                if (data[data.length - 1].end_time != null) {
                    roomInfo.numOfGames = data.length + 1;
                    //roomInfo.eachBankers.push(game.button);
                    game.roomInfo.bcheckfinish = false;
                } else {
                    roomInfo.numOfGames = data.length;
                }
            }
        });
    }
}

function delayToBegin(game) {
    (function () {
        setTimeout(function () {
            //操作完了就开始游戏
            gameBeginPush(game);
            if (!game.roomInfo.bcheckfinish) {
                db.store_shisanshui_eachround_history(game, game.roomInfo);
            } else {
                game.roomInfo.bcheckfinish = false;
            }
        }, 3000);
    })(game);
}

function gameBeginPush(game) {
    //房间信息
    var roomInfo = game.roomInfo;

    //剩多少张牌
    var numOfMJ = game.cards.length - game.currentIndex;

    for (var i = 0; i < game.gameSeats.length; ++i) {
        var userId = game.gameSeats[i].userId;

        //通知玩家手牌
        game.gameSeats[i].holds = card.sortPai(game.gameSeats[i].holds);
        userMgr.sendMsg(userId, 'game_holds_push', game.gameSeats[i].holds);
        log.debug("begin holds == ", game.gameSeats[i].userId, game.gameSeats[i].holds);

        var retType = card.calCardRes(userId, game.gameSeats[i].holds);
        if (retType != null) {
            userMgr.sendMsg(userId, 'card_type_push', retType);
            log.debug("card type == ", retType);
        }

        //通知还剩多少局
        console.log("game_num_push ", roomInfo.numOfGames);
        userMgr.sendMsg(userId, 'game_num_push', roomInfo.numOfGames);

        //游戏开始通知
        userMgr.sendMsg(userId, 'game_begin_push', { banker: game.button });

        if (i > 0 && roomInfo.conf.roomType == 1) {
            db.cost_gems(userId, roomInfo.cost);
        }
    }

    //游戏状态推送
    game.state = constant.GameStatus.PYAYING;
    userMgr.broadcastInRoom('game_status_push', { state: game.state }, game.gameSeats[0].userId, true);
}

//洗牌
function shuffle(game) {
    //0~12 黑桃 13~25 红桃 26~38 梅花 39~51 方块  值为从2到A
    var maxPaiNum = 0;
    var index = 0;
    if (game.conf.duoSe == 1) {
        if (game.gameSeats.length == 6) {  //多2色
            game.cards = new Array(78);
            maxPaiNum = 78;
        } else {
            game.cards = new Array(65);
            maxPaiNum = 65;
        }
    } else {
        game.cards = new Array(52);
        maxPaiNum = 52;
    }
    for (var i = 0; i < maxPaiNum; ++i) {
        if (i >= 52) {
            game.cards[index] = (i % 52) + 13;
        } else {
            game.cards[index] = i;
        }
        index++;
    }

    //洗牌
    for (i = 0; i < game.cards.length; ++i) {
        var lastIndex = game.cards.length - 1 - i;
        index = Math.floor(Math.random() * lastIndex);
        var t = game.cards[index];
        game.cards[index] = game.cards[lastIndex];
        game.cards[lastIndex] = t;
    }
}

function isConfigPais(game) {
    // 判断是否配牌了
    var isConfig = false;
    for (var i = 0; i < game.gameSeats.length; i++) {
        log.debug(game.gameSeats[i].isConfigPai);
        if (game.gameSeats[i].isConfigPai === 1) {
            isConfig = true;
        }
    }
    return isConfig;
}

//发牌
function deal(game) {
    //强制清0
    game.currentIndex = 0;
    //每人13张 一共 13*4 ＝ 52 庄家多一张 53张
    game.button = 0;
    var seatIndex = game.button;
    var seatIndex = 0;
    for (var i = 0; i < 13 * game.gameSeats.length; i++) {
        if (game.gameSeats[seatIndex].holds == null) {
            game.gameSeats[seatIndex].holds = [];
        }
        //摸牌
        mopai(game, seatIndex);

        //下一个
        seatIndex++;
        seatIndex %= game.gameSeats.length;
    }

    //设置庄家
    game.turn = game.button;
}

//摸牌
function mopai(game, seatIndex) {
    // 荒庄
    if (game.currentIndex === game.cards.length) {
        return -1;
    }
    var seatData = game.gameSeats[seatIndex];
    var pai = game.cards[game.currentIndex];
    seatData.holds.push(pai);

    //统计牌的数目
    if (seatData.countMap[pai] == null) {
        seatData.countMap[pai] = 1;
    }
    else {
        seatData.countMap[pai] += 1;
    }
    game.currentIndex++;
    return pai;
}

//获取配牌器配置
exports.getPeipaiConfig = function (userId) {
    db.isCanMoAnyPai(userId, function (ret) {
        userMgr.sendMsg(userId, 'get_pei_pai_config_push', ret.isMoAnyPai);
    });
}

//期望的摸牌
exports.hopeMoPai = function (userId, pai) {
    return;
}

// 定缺
exports.dingQue = function (userId, type) {
    return;
};

//测距
exports.userDistance = function (_msgUserId, userIds) {
    return;
};

//报听
exports.baoTing = function (userId, isBaoTing) {
    return;
};

//出牌
exports.chuPai = function (userId, pai) {
    return;
};

function getSeatIndex(userId) {
    var seatIndex = roomMgr.getUserSeat(userId);
    if (seatIndex == null) {
        return null;
    }
    return seatIndex;
}

function getGameByUserID(userId) {
    var roomId = roomMgr.getUserRoom(userId);
    if (roomId == null) {
        return null;
    }
    var game = games[roomId];
    return game;
}

//串行
function seriesSaveToDB(game, roomInfo, roomId, userId, totalRes) {
    async.series({
        store: function (callback) {
            //创建游戏
            // setTimeout(function () {
            //     var strActions = JSON.stringify(game.actionList);
            //     construct_game_base_info(game);
            //     db.store_game_round_result(game.roomInfo.uuid, game.gameIndex, game.baseInfoJson, strActions, dbresult);
            // }, 500);

            callback(null, 1);
        },
        update_gems: function (callback) {
            roomRes[roomId] = totalRes;
            roomRes[roomId].isSend = false;
            roomRes[roomId].saveTime = Date.now();
            clearDissolvingList(roomId);
            callback(null, 2);
        },
        release: function (callback) {
            //是否满足局数限制解散房间
            if (totalRes != null && roomInfo.numOfGames == roomInfo.conf.maxGames) {
                //如果局数已够，则进行整体结算，并关闭房间
                userMgr.broadcastInRoom('game_over_push', totalRes, userId, true);
                setTimeout(function () {
                    userMgr.kickAllInRoom(roomId);
                    roomMgr.destroy(roomId);
                    db.archive_games(roomInfo.uuid);
                }, 3000 * game.gameSeats.length + 2000);
            }
        }
    }, function (err, results) {
        log.debug(results);
    });
}

//清空解散列表
function clearDissolvingList(roomId) {
    for (let i = dissolvingList.length - 1; i >= 0; --i) {
        if (dissolvingList[i] == roomId) {
            dissolvingList.splice(i, 1);
        }
    }
}

function getSeatsIdByUsersId(game, usersId) {
    var SeatsId = usersId.map(function (userId) {
        return _.find(game.gameSeats, function (seatData) { return seatData.userId === userId; }).seatIndex;
    });
    return SeatsId;
}

//游戏结算 operStatus --操作状态, 0--点击胡牌后进入 1--黄庄情况下结算 2--强制解散
function doGameOver(game, userId, operStatus, totalRes) {
    var roomId = roomMgr.getUserRoom(userId);
    if (roomId == null) {
        return;
    }
    var roomInfo = roomMgr.getRoom(roomId);
    if (roomInfo == null) {
        return;
    }

    var dbresult = [0, 0, 0, 0];
    var fnNoticeResult = function () {

        if (game == null) {
            var roomData = roomRes[roomId];
            if (roomData != null) {
                roomData.isend = true;
                roomData.isSend = true;
            }
        } else {
            roomRes[roomId] = totalRes;
            roomRes[roomId].isSend = false;
            roomRes[roomId].saveTime = Date.now();
        }

        clearDissolvingList(roomId);
        userMgr.broadcastInRoom('game_over_push', totalRes, userId, true);
        console.log("force game end totalRes = ", totalRes);

        //释放房间
        setTimeout(function () {
            userMgr.kickAllInRoom(roomId);
            roomMgr.destroy(roomId);
            db.archive_games(roomInfo.uuid);
        }, 3000 * roomInfo.seats.length + 2000);
    }

    if (game != null) {
        game.state = constant.GameStatus.GAMEOVER;
        userMgr.broadcastInRoom('game_status_push', { state: game.state }, userId, true);

        //赢家
        for (var i = 0; i < game.gameSeats.length; ++i) {
            var rs = roomInfo.seats[i];
            if (rs != null) {
                rs.ready = false;
            }
            var sd = game.gameSeats[i];
            if (sd != null) {
                delete gameSeatsOfUsers[sd.userId];
                card.deleteUserCard(sd.userId);
                channel.deleteUserChannel(sd.userId);
            }
        }
        delete games[roomId];
    }

    //更新战绩
    db.update_shisanshui_each_round_history(roomInfo);

    if (operStatus == 2 || game == null) {
        log.debug("force game end");
        if (roomInfo.conf.roomType == 0 && game != null) {
            db.cost_gems(game.gameSeats[0].userId, -1 * roomInfo.cost);
        } else if (roomInfo.conf.roomType == 1 && game != null) {
            for (let i = 0; i < game.gameSeats.length; ++i) {
                db.cost_gems(game.gameSeats[i].userId, -1 * roomInfo.cost / game.gameSeats.length);
            }
        }

        fnNoticeResult();
    } else {

        //保存游戏
        seriesSaveToDB(game, roomInfo, roomId, userId, totalRes);
    }
}

exports.reconnectOK = function (userId) {
    var roomId = roomMgr.getUserRoom(userId);
    if (roomId == null) {
        return;
    }
    var roomInfo = roomMgr.getRoom(roomId);
    if (roomInfo == null) {
        return;
    }

    var data = {
        userid: userId,
        online: true
    };

    //通知房间内其它玩家
    userMgr.broadcastInRoom('user_state_push', data, userId, true);

    var game = games[roomId];
    if (game == null) {
        var typeInfo = constant.CreateRoomInfo.type[roomInfo.conf.type];
        if (roomInfo.seats.length == typeInfo.seatlen) {
            var seats = [];
            var flag = false;
            var ready = false;
            for (var i = 0; i < roomInfo.seats.length; ++i) {
                var seat = roomInfo.seats[i];

                seats.push({
                    userid: seat.userId,
                    ip: seat.ip,
                    score: seat.score,
                    name: seat.name,
                    online: userMgr.isOnline(seat.userId),
                    ready: seat.ready,
                    seatindex: i
                });
                if (seat.ready == false || userMgr.isOnline(seat.userId) == false) {
                    flag = true;
                }
                if (seat.userId == userId) {
                    ready = seat.ready;
                }
            }

            //通知前端
            if (false == ready && roomRes[roomId] != null) {
                var data = roomRes[roomId];
                data.isSend = true;
                //userMgr.sendMsg(userId, 'game_over_push', data);
            }
            else {
                var ret = {
                    roomid: roomInfo.id,
                    conf: roomInfo.conf,
                    numofgames: roomInfo.numOfGames,
                    seats: seats
                };
                userMgr.sendMsg(userId, 'reconnect_prepare_push', ret);
            }

            if (flag) {
                return;
            }

            //4个人到齐了，并且都准备好了，则开始新的一局
            exports.begin(roomId);
        }
    }
    else {
        roomMgr.setReady(userId, true);
        var numOfMJ = game.cards.length - game.currentIndex;
        var gameData = {
            state: game.state,
            numofmj: numOfMJ,
            button: game.button,
            turn: game.turn,
            chuPai: game.chuPai,
            caishen: game.caishenPai,
            dishu: game.dishu,
            paidun: game.paidun,
            roomid: roomInfo.id,
            conf: roomInfo.conf,
            numofgames: roomInfo.numOfGames,
            showPai: (game.chuPaiData == null) ? {} : game.chuPaiData,
        };
        log.debug("game round == " + roomInfo.numofgames + " game state == " + game.state);
        gameData.seats = [];
        for (var i = 0; i < game.gameSeats.length; ++i) {
            var gameSeat = game.gameSeats[i];
            var rs = roomInfo.seats[i];
            if (i == game.button && constant.GameStatus.IDLE == game.state) {
                game.canChuPai = true;
            }

            var seat = {
                userid: gameSeat.userId,
                folds: gameSeat.lestFolds,
                chis: gameSeat.chis,
                que: gameSeat.que,
                angangs: gameSeat.angangs,
                diangangs: gameSeat.diangangs,
                wangangs: gameSeat.wangangs,
                pengs: gameSeat.pengs,
                hued: gameSeat.hued,
                iszimo: gameSeat.iszimo,
                baoTingStatus: gameSeat.acChuPaiStatus,
                ip: rs.ip,
                score: rs.score,
                name: rs.name,
                online: userMgr.isOnline(rs.userId),
                ready: rs.ready,
                seatindex: i,
                jiPaiTypes: 0,//_Jipai.getZenRenJiBySeatIndex(game, gameSeat.seatIndex)
                channelStatus: gameSeat.isSubmit
            };
            if (gameSeat.userId == userId) {
                seat.holds = gameSeat.holds;
                //var lestPai = card.getLestPai(userId);
                //seat.holds = (lestPai == null) ? gameSeat.holds : lestPai;
                seat.type = card.calCardRes(userId, gameSeat.holds);
                seat.channel = [];
                for (let j = cn.channelNO.HEAD; j <= cn.channelNO.BOTTON; ++j) {
                    var channelRes = channel.getChannelData(userId, j);
                    seat.channel.push(channelRes);
                }
            }
            gameData.seats.push(seat);
        }

        log.debug(gameData);

        //同步整个信息给客户端
        userMgr.sendMsg(userId, 'reconnect_ok_push', gameData);

        //发送解散数据
        sendDissolvingMsg(userId, roomId, roomInfo);
    }
}

exports.setReady = function (userId) {
    var roomId = roomMgr.getUserRoom(userId);
    if (roomId == null) {
        return;
    }
    var roomInfo = roomMgr.getRoom(roomId);
    if (roomInfo == null) {
        return;
    }

    roomMgr.setReady(userId, true);
    //db.get_user_isConfig_pai(userId, function (isConfigPai) {
    //roomMgr.setConfigPaiStatus(userId, isConfigPai);
    var game = games[roomId];
    if (game == null) {
        var typeInfo = constant.CreateRoomInfo.type[roomInfo.conf.type];
        if (roomInfo.seats.length == typeInfo.seatlen) {
            for (var i = 0; i < roomInfo.seats.length; ++i) {
                var seat = roomInfo.seats[i];
                if (seat.ready == false || userMgr.isOnline(seat.userId) == false) {
                    return;
                }
            }
            //4个人到齐了，并且都准备好了，则开始新的一局
            exports.begin(roomId);
        }
    }
    else {
        //游戏状态推送
        userMgr.broadcastInRoom('game_status_push', { state: game.state }, userId, true);
        var numOfMJ = game.cards.length - game.currentIndex;
        var remainingGames = roomInfo.conf.maxGames - roomInfo.numOfGames;
        var gameData = {
            state: game.state,
            numofmj: numOfMJ,
            button: game.button,
            turn: game.turn,
            chuPai: game.chuPai,
            caishen: game.caishenPai,
            dishu: game.dishu,
            paidun: game.paidun,
            showPai: (game.chuPaiData == null) ? {} : game.chuPaiData,
        };
        gameData.seats = [];
        var seatData = null;
        for (var i = 0; i < game.gameSeats.length; ++i) {
            var gameSeat = game.gameSeats[i];
            if (i === game.button && constant.GameStatus.IDLE === game.state) {
                game.canChuPai = true;
            }
            var seat = {
                userid: gameSeat.userId,
                folds: gameSeat.lestFolds,
                chis: gameSeat.chis,
                angangs: gameSeat.angangs,
                diangangs: gameSeat.diangangs,
                wangangs: gameSeat.wangangs,
                pengs: gameSeat.pengs,
                hued: gameSeat.hued,
                iszimo: gameSeat.iszimo,
                que: gameSeat.que,
                baoTingStatus: gameSeat.acChuPaiStatus,
                jiPaiTypes: 0, //_Jipai.getZenRenJiBySeatIndex(game, gameSeat.seatIndex)
                channelStatus: gameSeat.isSubmit
            }
            if (gameSeat.userId == userId) {
                seat.holds = gameSeat.holds;
                //var lestPai = card.getLestPai(userId);
                //seat.holds = (lestPai == null) ? gameSeat.holds : lestPai;
                console.log("game sync holds = ", seat.holds);
                seat.type = card.calCardRes(userId, gameSeat.holds);
                seat.channel = [];
                for (let j = cn.channelNO.HEAD; j <= cn.channelNO.BOTTON; ++j) {
                    var channelRes = channel.getChannelData(userId, j)
                    seat.channel.push(channelRes);
                }
            }
            gameData.seats.push(seat);
            var data = {
                userid: gameSeat.userId,
                online: userMgr.isOnline(gameSeat.userId),
            };
            //通知房间内其它玩家
            userMgr.broadcastInRoom('user_state_push', data, userId, true);
        }

        //同步整个信息给客户端
        userMgr.sendMsg(userId, 'game_sync_push', gameData);
        setTimeout(function () {
            //发送解散数据
            sendDissolvingMsg(userId, roomId, roomInfo);
        }, 1500);
    }
    //});
};

//发送解散通知
function sendDissolvingMsg(userId, roomId, roomInfo) {
    if (dissolvingList.indexOf(roomId) != -1) {
        if (roomInfo != null && roomInfo.dr != null) {
            var dr = roomInfo.dr;
            if (dr.endTime != null) {
                var ramaingTime = (dr.endTime - Date.now()) / 1000;
                var data = {
                    time: ramaingTime,
                    states: dr.states
                }
                console.log("set ready game_sync_push dissolve_notice_push release room ", userId, roomId);
                userMgr.broadcastInRoom('dissolve_notice_push', data, userId, true);
            }
        }
    }
}

function construct_game_base_info(game) {
    var typeInfo = constant.CreateRoomInfo.type[game.conf.type];
    var baseInfo = {
        type: game.conf.type,
        button: game.button,
        index: game.gameIndex,
        cards: game.cards,
        game_seats: new Array(typeInfo.seatlen)
    };

    for (var i = 0; i < game.gameSeats.length; ++i) {
        baseInfo.game_seats[i] = game.gameSeats[i].holds;
    }
    game.baseInfoJson = JSON.stringify(baseInfo);
}

exports.peng = function (userId) {
    return;
};

exports.isPlaying = function (userId) {
    var seatData = gameSeatsOfUsers[userId];
    if (seatData == null) {
        return false;
    }

    var game = seatData.game;
    if (game.state == constant.GameStatus.IDLE || game.state === constant.GameStatus.PYAYING) {
        return false;
    }
    return true;
};

//杠操作
exports.gang = function (userId, pai) {
    return;
};

exports.hu = function (userId) {
    return;
};

//弃牌
exports.guo = function (userId) {
    return;
};

exports.hasBegan = function (roomId) {
    var game = games[roomId];
    // if (game != null) {
    //     return true;
    // }
    // var roomInfo = roomMgr.getRoom(roomId);
    // if (roomInfo != null) {
    //     return roomInfo.numOfGames > 0;
    // }
    // return false;

    if (game != null) {
        if (game.state == constant.GameStatus.PYAYING) {
            return true;
        } else {
            return false;
        }
    }
    return false;
};

exports.doDissolve = function (roomId) {
    var roomInfo = roomMgr.getRoom(roomId);
    if (roomInfo == null) {
        return null;
    }

    var game = games[roomId];
    var totalRes = getTotalScore(game, roomInfo, true);
    doGameOver(game, roomInfo.seats[0].userId, 2, totalRes);
};

exports.dissolveRequest = function (roomId, userId) {
    var roomInfo = roomMgr.getRoom(roomId);
    if (roomInfo == null) {
        return null;
    }

    if (roomInfo.dr != null) {
        log.debug("dissolveRequest room info dr ", roomInfo.dr, dissolvingList);
        return roomInfo;
    }

    var seatIndex = roomMgr.getUserSeat(userId);
    if (seatIndex == null) {
        return null;
    }

    var typeInfo = constant.CreateRoomInfo.type[roomInfo.conf.type];
    roomInfo.dr = {
        endTime: Date.now() + 180000,
        states: new Array(typeInfo.seatlen),
    };
    for (var i = 0; i < typeInfo.seatlen; ++i) {
        if (i != seatIndex) {
            roomInfo.dr.states[i] = false;
        } else {
            roomInfo.dr.states[seatIndex] = true;
        }
    }
    if (dissolvingList.indexOf(roomId) == -1) {
        dissolvingList.push(roomId);
    }
    log.debug("dissolveRequest ", dissolvingList, roomId, userId, roomInfo.dr, typeInfo.seatlen);

    return roomInfo;
};

exports.dissolveAgree = function (roomId, userId, agree) {
    var roomInfo = roomMgr.getRoom(roomId);
    if (roomInfo == null) {
        return null;
    }

    if (roomInfo.dr == null) {
        log.debug("dissolveAgree room info dr 1 ", roomInfo.dr, dissolvingList);
        return roomInfo;
    }

    var seatIndex = roomMgr.getUserSeat(userId);
    if (seatIndex == null) {
        return null;
    }

    if (agree) {
        roomInfo.dr.states[seatIndex] = true;
        log.debug("dissolveAgree room info dr 2 ", roomInfo.dr, dissolvingList);
    }
    else {
        roomInfo.dr = null;
        var idx = dissolvingList.indexOf(roomId);
        if (idx != -1) {
            dissolvingList.splice(idx, 1);
            log.debug("cancel dissolveAgree ", dissolvingList, roomId, userId);
        }
    }
    return roomInfo;
};

function shuffleTest(game) {
    //17+3*16 = 65张牌
    var buttonPai = [];//[0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,6];
    var player1 = [];//[9,9,9,10,10,10,11,11,11,12,12,12,13,13,13,14];
    var player2 = [];//[18,18,18,19,19,19,20,20,20,21,21,21,22,22,22,23];
    var player3 = [];//[27,27,27,28,28,28,29,29,29,30,30,30,31,31,31,33];
    var caishenpai = 0;

    //是否测试
    var bFlag = configPai.GetHoldsPai(buttonPai, player1, player2, player3, function (data) {
        if (data != null) {
            //game.caishenPai = data;
        }
    });
    if (!bFlag) {
        //洗牌
        shuffle(game);

        //发牌
        deal(game);

        return;
    }

    var cards = game.cards;
    //筒 0 ~ 8 表示筒子,条 9 ~ 17表示条子,万 18 ~ 26表示万
    var index = 0;
    var mahjongsTmp = [];
    // for (var i = 0; i <= maxPai; ++i) {
    //     for (var c = 0; c < 4; ++c) {
    //         mahjongsTmp[index] = i;
    //         game.cards[index] = i;
    //         index++;
    //     }
    // }
    //0~12 黑桃 13~25 红桃 26~38 梅花 39~51 方块  值为从2到A
    for (var i = 0; i <= maxPai; ++i) {
        mahjongsTmp[index] = i;
        cards[index] = i;
        index++;
    }

    index = 0;
    for (var i = 0; i < 13; ++i) {
        game.cards[index] = buttonPai[i];
        ++index;
        game.cards[index] = player1[i];
        ++index;
        // game.cards[index] = player2[i];
        // ++index;
        // game.cards[index] = player3[i];
        // ++index;
    }
    //game.cards[index] = buttonPai[13];
    //++index;

    //手牌
    game.button = 0;
    for (var i = 0; i < 13; ++i) {
        if (game.gameSeats[game.button].holds == null) {
            game.gameSeats[game.button].holds = [];
        }
        game.gameSeats[game.button].holds.push(buttonPai[i]);
        if (game.gameSeats[game.button].countMap[buttonPai[i]] == null) {
            game.gameSeats[game.button].countMap[buttonPai[i]] = 1;
        }
        else {
            game.gameSeats[game.button].countMap[buttonPai[i]] += 1;
        }
        if (game.gameSeats[(game.button + 1) % game.gameSeats.length].holds == null) {
            game.gameSeats[(game.button + 1) % game.gameSeats.length].holds = [];
        }
        game.gameSeats[(game.button + 1) % game.gameSeats.length].holds.push(player1[i]);
        if (game.gameSeats[(game.button + 1) % game.gameSeats.length].countMap[player1[i]] == null) {
            game.gameSeats[(game.button + 1) % game.gameSeats.length].countMap[player1[i]] = 1;
        }
        else {
            game.gameSeats[(game.button + 1) % game.gameSeats.length].countMap[player1[i]] += 1;
        }
        // game.gameSeats[(game.button + 2) % game.gameSeats.length].holds.push(player2[i]);
        // if (game.gameSeats[(game.button + 2) % game.gameSeats.length].countMap[player2[i]] == null) {
        //     game.gameSeats[(game.button + 2) % game.gameSeats.length].countMap[player2[i]] = 1;
        // }
        // else {
        //     game.gameSeats[(game.button + 2) % game.gameSeats.length].countMap[player2[i]] += 1;
        // }
        // game.gameSeats[(game.button + 3) % game.gameSeats.length].holds.push(player3[i]);
        // if (game.gameSeats[(game.button + 3) % game.gameSeats.length].countMap[player3[i]] == null) {
        //     game.gameSeats[(game.button + 3) % game.gameSeats.length].countMap[player3[i]] = 1;
        // }
        // else {
        //     game.gameSeats[(game.button + 3) % game.gameSeats.length].countMap[player3[i]] += 1;
        // }
    }

    // game.gameSeats[game.button].holds.push(buttonPai[13]);
    // if (game.gameSeats[game.button].countMap[buttonPai[13]] == null) {
    //     game.gameSeats[game.button].countMap[buttonPai[13]] = 1;
    // }
    // else {
    //     game.gameSeats[game.button].countMap[buttonPai[13]] += 1;
    // }

    // // //检查胡，直杠，弯杠
    // checkCanWanGang(game, game.gameSeats[game.button], buttonPai[13]);

    // // //检查看是否可以和
    // checkCanHu(game, game.gameSeats[game.button], buttonPai[13], 1);

    //从麻将堆里减掉发牌的牌
    for (var j = mahjongsTmp.length - 1; j >= 0; --j) {
        for (var k = buttonPai.length - 1; k >= 0; --k) {
            if (mahjongsTmp[j] == buttonPai[k]) {
                mahjongsTmp.splice(j, 1);
                buttonPai.splice(k, 1);
                break;
            }
        }
    }
    for (var j = mahjongsTmp.length - 1; j >= 0; --j) {
        for (var k = player1.length - 1; k >= 0; --k) {
            if (mahjongsTmp[j] == player1[k]) {
                mahjongsTmp.splice(j, 1);
                player1.splice(k, 1);
                break;
            }
        }
    }

    for (var j = mahjongsTmp.length - 1; j >= 0; --j) {
        for (var k = player2.length - 1; k >= 0; --k) {
            if (mahjongsTmp[j] == player2[k]) {
                mahjongsTmp.splice(j, 1);
                player2.splice(k, 1);
                break;
            }
        }
    }
    for (var j = mahjongsTmp.length - 1; j >= 0; --j) {
        for (var k = player3.length - 1; k >= 0; --k) {
            if (mahjongsTmp[j] == player3[k]) {
                mahjongsTmp.splice(j, 1);
                player3.splice(k, 1);
                break;
            }
        }
    }

    //洗剩余牌
    for (var i = 0; i < mahjongsTmp.length; ++i) {
        var lastIndex = mahjongsTmp.length - 1 - i;
        var index2 = Math.floor(Math.random() * lastIndex);
        var t = mahjongsTmp[index2];
        mahjongsTmp[index2] = mahjongsTmp[lastIndex];
        mahjongsTmp[lastIndex] = t;
    }

    for (var i = 0; i < mahjongsTmp.length; ++i) {
        game.cards[index] = mahjongsTmp[i];
        ++index;
    }
    //game.cards[53] = 12;
    // game.cards[40] = 3;
    // game.cards[41] = 3;
    // game.cards[42] = 3;
    //game.cards[53] = 11;
    //game.cards[53] = 11;
    // game.cards[57] = 5;
    // game.cards[61] = 4;

    game.turn = game.button;
    //game.currentIndex = 27;
}

function TestModel(game) {
    shuffleTest(game);
}

//获取牌型对应的牌
exports.getCardPaiOfType = function (userId, type) {
    if (userId == null || type < 0 || type > 8) {
        log.info("err: getCardPaiOfType userId type ", userId, type);
        return;
    }
    if (typeof type == 'string') {
        type = Number.parseInt(type);
    }
    var isSetChannel = channel.isSetChannel(userId);
    var lestType = [];
    if (!isSetChannel) {
        var seatData = gameSeatsOfUsers[userId];
        if (seatData != null) {
            lestType = card.calCardRes(userId, seatData.holds);
        }
    } else {
        lestType = card.calCardRes(userId);
    }
    console.log("lest type from client ", lestType, type);
    if (lestType != null && lestType.length > 0 && lestType.indexOf(type) != -1) {
        let lestPai = [].concat(card.getLestPai(userId));
        let retPais = card.getUserCardInfo(userId, type);
        if (retPais == null) {
            console.log("not get return pai ", type);
            return;
        }
        var retIndex = [];
        if (lestPai != null) {
            if (!isSetChannel) {
                retIndex = card.returnPaisIndex(userId, retPais, seatData.holds);
            } else {
                retIndex = card.returnPaisIndex(userId, retPais, lestPai);
            }
        } else {
            console.log("err: can not find type pai ", type);
        }
        console.log("index type ", type, retPais, retIndex, lestPai);
        userMgr.sendMsg(userId, 'card_pai_push', { retIndex: retIndex, type: type });
    } else {
        console.log("err: client send type is , all lest type is ", type, lestType);
    }
}

//获取剩余牌对应的牌型
exports.chuCard = function (userId, cardData) {
    cardData = JSON.parse(cardData);
    if (cardData == null || typeof cardData != 'object') {
        log.error("err: receive client data error ", userId, cardData);
        return;
    }

    //校验
    // var isSet = channel.isSetChannelNO(userId, cardData.channel);
    // if (isSet) {
    //     console.log("err: receive client channel NO error ", userId, cardData.channel);
    //     sendOriginData(userId, cardData);
    //     return;
    // }

    if (cardData.channel < cn.channelNO.HEAD || cardData.channel > cn.channelNO.BOTTON) {
        log.error("err: receive client channel error ", userId, cardData.channel);
        sendOriginData(userId, cardData);
        return;
    }
    if ((cardData.channel == cn.channelNO.HEAD && cardData.pai.length != 3)
        || (cardData.channel == cn.channelNO.MIDDLE && cardData.pai.length != 5)
        || (cardData.channel == cn.channelNO.BOTTON && cardData.pai.length != 5)) {
        log.error("err: receive client channel pai count error ", userId, cardData.channel, cardData.pai);
        sendOriginData(userId, cardData);
        return;
    }

    var paiCountMap = {};
    var seatData = gameSeatsOfUsers[userId];
    for (var i = 0; i < cardData.pai.length; ++i) {
        var index = seatData.holds.indexOf(cardData.pai[i]);
        if (index == -1) {
            log.error("err: receive client pai data error ", userId, cardData.pai);
            sendOriginData(userId, cardData);
            return;
        }
        paiCountMap[cardData.pai[i]] = (paiCountMap[cardData.pai[i]] === undefined) ? 1 : ++paiCountMap[cardData.pai[i]];
    }
    for (let pai in paiCountMap) {
        let paiVal = Number.parseInt(pai);
        if (paiCountMap[paiVal] > seatData.countMap[paiVal]) {
            log.error("err: receive client a pai num error ", userId, paiVal, paiCountMap[paiVal]);
            sendOriginData(userId, cardData);
            return;
        }
    }
    cardData.pai = card.sortPai(cardData.pai);

    console.log("chuCard type 1 ", cardData.pai, cardData.type);
    var channelPaiNum = cardData.pai.length;
    var type = card.calCardType(userId, cardData.pai, channelPaiNum);
    console.log("chuCard type 2 ", cardData.pai, type);

    //设置通道的牌型
    if (cardData.type != -1) {
        if (type.indexOf(cardData.type) == -1) {
            console.log("err: client send type error ", cardData.type);
            //return;
            cardData.type = (type.length > 0) ? type[0] : cn.cardType.WULONG;
        }
    } else {
        cardData.type = (type.length > 0) ? type[0] : cn.cardType.WULONG;
    }
    console.log("chuCard type 4 ", cardData.pai, cardData.type);

    var result = channel.setChannelData(userId, cardData.channel, cardData.type, cardData.pai);
    if (result == null) {

        //返回操作成功以及剩余牌型
        card.delSelPaiFromHolds(userId, cardData.pai);
        var retPaiTypes = card.calCardRes(userId);
        var retPais = card.getLestPai(userId);
        console.log("chu card success ", retPaiTypes, retPais, cardData.type);

        //发送剩余数据
        userMgr.sendMsg(userId, 'chu_card_push', {
            lestPaiTypes: retPaiTypes, lestPais: retPais, type: cardData.type,
            channel: cardData.channel, isError: 0, errMsg: ''
        });
    } else {
        sendOriginData(userId, cardData);
    }
}

//发送原有数据
function sendOriginData(userId, cardData, result) {
    //返回剩余牌型
    var retPaiTypes = card.calCardRes(userId);
    var retPais = card.getLestPai(userId);
    console.log("chu card failed ", retPaiTypes, retPais, cardData.type);
    var errMsg = "";
    if (result != null) {
        errMsg = "通道" + result.channel1 + "必须小于通道" + result.channel2 + ", 请重新选择!";
    }

    //发送剩余数据
    userMgr.sendMsg(userId, 'chu_card_push', {
        lestPaiTypes: retPaiTypes, lestPais: retPais, type: cardData.type,
        channel: cardData.channel, isError: 1, errMsg: errMsg
    });
}

//取消通道设置
exports.cancelChuCard = function (userId, channelNO) {
    //校验
    if (!channel.isSetChannelNO(userId, channelNO)) {
        console.log("err: client has cancel channel data ", userId, channelNO);
    } else {
        var data = channel.getChannelData(userId, channelNO);
        if (data != null) {
            var lestPaisType = [];
            var lestPais = [];
            console.log("channel pai ", userId, channelNO, data.pai);
            card.pushPaisToUserCard(userId, data.pai);
            if (channel.isSetChannel(userId)) {
                lestPaisType = card.calCardRes(userId);
            } else {
                var seatData = gameSeatsOfUsers[userId];
                if (seatData != null) {
                    lestPaisType = card.calCardRes(userId, seatData.holds);
                }
            }
            lestPais = card.getLestPai(userId);
            channel.cancelChannelNO(userId, channelNO);
            console.log("lest type lest pai ", userId, channelNO, lestPaisType, lestPais);
            userMgr.sendMsg(userId, 'cannel_chu_pai_push', { lestPaisType: lestPaisType, lestPais: lestPais });
        }
    }
}

//确认出牌
exports.playOut = function (userId, isOut) {
    var seatData = gameSeatsOfUsers[userId];
    if (seatData == null) {
        return;
    }
    if (typeof isOut == 'string') {
        isOut = Number.parseInt(isOut);
    }
    seatData.isOut = isOut;
    userMgr.broadcastInRoom('play_out_ready', { userId: userId, ready: (isOut == 1) ? true : false }, userId, true);
    if (isOut == 1) {
        seatData.isSubmit = true;
    }

    var userPlayResult = {};
    var userScore = {};
    if (seatData == null || seatData.game == null) {
        console.log("seat data is null ", userId);
        return;
    }
    var roomInfo = seatData.game.roomInfo;
    if (roomInfo == null) {
        console.log("room info is null ", roomInfo);
        return;
    }
    var roomId = roomInfo.id;
    var seats = roomInfo.seats;
    var userResult = [];
    var quanLeiDa = {};         //是否全垒打
    var game = seatData.game;
    if (game == null) {
        return;
    }

    for (let i = 0; i < seats.length; ++i) {
        var userId1 = seats[i].userId;
        for (let j = i + 1; j < seats.length; ++j) {
            var userId2 = seats[j].userId;
            if (gameSeatsOfUsers[userId1].isOut === undefined || gameSeatsOfUsers[userId1].isOut == 0
                || gameSeatsOfUsers[userId2].isOut === undefined || gameSeatsOfUsers[userId2].isOut == 0) {
                return;
            }
            var score1 = 0;
            var score2 = 0;
            var daQiang = [];  //打枪
            for (var k = cn.channelNO.HEAD; k <= cn.channelNO.BOTTON; ++k) {
                var res = channel.compare(userId1, userId2, k);
                var userData1 = channel.getChannelData(userId1, k);
                var userData2 = channel.getChannelData(userId2, k);
                //console.log("channel and data ", k, userData1, userData2);
                if (res == cn.compareResult.ERROR || res == cn.compareResult.EQUAL) {
                    console.log("channel no data ", k, userData1, userData2);
                    continue;
                }

                //统计输赢一道的分数
                addScorePerChannel(userPlayResult, userData1, userData2, userId1, userId2, k, res);
                score1 += res;
                score2 -= res;

                //冲三
                if (k == cn.channelNO.HEAD) {
                    if ((userData1.type == cn.cardType.SANTIAO && res == cn.compareResult.GREATER)
                        || (userData2.type == cn.cardType.SANTIAO && res == cn.compareResult.LESS)) {
                        score1 += (2 * res);
                        score2 -= (2 * res);
                    }
                } else if (k == cn.channelNO.MIDDLE) {   //中墩葫芦
                    if ((userData1.type == cn.cardType.HULU && res == cn.compareResult.GREATER)
                        || (userData2.type == cn.cardType.HULU && res == cn.compareResult.LESS)) {
                        score1 += res;
                        score2 -= res;
                    } else if ((userData1.type == cn.cardType.TIEZHI && res == cn.compareResult.GREATER)
                        || (userData2.type == cn.cardType.TIEZHI && res == cn.compareResult.LESS)) {
                        score1 += 8 * res;
                        score2 -= 8 * res;
                    } else if ((userData1.type == cn.cardType.TONGHUASHUN && res == cn.compareResult.GREATER)
                        || (userData2.type == cn.cardType.TONGHUASHUN && res == cn.compareResult.LESS)) {
                        score1 += 10 * res;
                        score2 -= 10 * res;
                    } else if ((userData1.type == cn.cardType.WUTONG && res == cn.compareResult.GREATER)
                        || (userData2.type == cn.cardType.WUTONG && res == cn.compareResult.LESS)) {
                        score1 += 20 * res;
                        score2 -= 20 * res;
                    }
                } else if (k == cn.channelNO.BOTTON) {
                    if ((userData1.type == cn.cardType.TIEZHI && res == cn.compareResult.GREATER)
                        || (userData2.type == cn.cardType.TIEZHI && res == cn.compareResult.LESS)) {
                        score1 += 4 * res;
                        score2 -= 4 * res;
                    } else if ((userData1.type == cn.cardType.TONGHUASHUN && res == cn.compareResult.GREATER)
                        || (userData2.type == cn.cardType.TONGHUASHUN && res == cn.compareResult.LESS)) {
                        score1 += 5 * res;
                        score2 -= 5 * res;
                    } else if ((userData1.type == cn.cardType.WUTONG && res == cn.compareResult.GREATER)
                        || (userData2.type == cn.cardType.WUTONG && res == cn.compareResult.LESS)) {
                        score1 += 10 * res;
                        score2 -= 10 * res;
                    }
                }
                daQiang.push(res);
            }
            if (daQiang.indexOf(cn.compareResult.EQUAL) == -1 && daQiang.indexOf(cn.compareResult.LESS) == -1) {
                if (game.conf.daQiangRule == 0) {
                    score1 += 1;
                    score2 -= 1;
                } else {
                    score1 += score2 * 2;
                    score2 -= score2 * 2;
                }
                if (quanLeiDa[userId1] === undefined) {
                    quanLeiDa[userId1] = [];
                }
                quanLeiDa[userId1].push(userId2);
            } else if (daQiang.indexOf(cn.compareResult.EQUAL) == -1 && daQiang.indexOf(cn.compareResult.GREATER) == -1) {
                if (game.conf.daQiangRule == 0) {
                    score1 -= 1;
                    score2 += 1;
                } else {
                    score1 += score2 * 2;
                    score2 -= score2 * 2;
                }
                if (quanLeiDa[userId2] === undefined) {
                    quanLeiDa[userId2] = [];
                }
                quanLeiDa[userId2].push(userId1);
            }
            userScore[userId1] = (userScore[userId1] == null) ? score1 : (userScore[userId1] + score1);
            userScore[userId2] = (userScore[userId2] == null) ? score2 : (userScore[userId2] + score2);
        }
        if (game.conf.zhuangMode == 1) {
            break;
        }
    }
    console.log("normal score userPlayResult ", userPlayResult);
    //全垒打算分
    for (let userId in quanLeiDa) {
        if (quanLeiDa[userId].length < 3) {
            continue;
        }
        for (let l = 0; l < quanLeiDa[userId].length; ++l) {
            let userTmpId = quanLeiDa[userId][l];
            userScore[userTmpId] -= (2 * userScore[userTmpId]);
            userScore[userId] += (2 * userScore[userTmpId]);
        }
    }

    //三同花 三顺子 六对半 四套三条 三分天下 三同花顺 一条龙 青龙
    if (game.conf.specialPaiType == 1) {
        for (let userId in userPlayResult) {
            var compareRes = userPlayResult[userId];
            if (compareRes == null) {
                continue;
            }
            if (card.isSpecialType(userId, cn.resType.YITIAOLONG)
                || card.isSpecialType(userId, cn.resType.QINGLONG)) {
                continue;
            }
            console.log("result data userId ", userId, compareRes);
            var userWinType = {};
            for (let i = 0; i < compareRes.length; ++i) {
                if (compareRes[i] == null) {
                    continue;
                }
                userWinType[compareRes[i].type] = (userWinType[compareRes[i].type] === undefined) ? 0 : ++userWinType[compareRes[i].type];
            }
            if (userWinType[cn.cardType.TONGHUASHUN] >= 2) {  //三同花顺
                setSanTongHuaShun(userId);
            } else if (userWinType[cn.cardType.TIEZHI] >= 4) {
                card.setSpecialType(userId, cn.resType.SANFENTIANXIA);
            } else if (userWinType[cn.cardType.SANTIAO] >= 4) {
                card.setSpecialType(userId, cn.resType.SITAOSANTIAO);
            } else if (userWinType[cn.cardType.DUIZI] >= 6) {
                card.setSpecialType(userId, cn.resType.LIUDUIBAN);
            } else if (userWinType[cn.cardType.TONGHUA] >= 3) {
                card.setSpecialType(userId, cn.resType.SANTONGHUA);
            } else if (userWinType[cn.cardType.SHUNZI] >= 2) {
                setSanShunzi(userId);
            }
        }

        //比较玩家间特殊牌型大小
        var winScore = 0;
        for (let i = 0; i < game.gameSeats.length; ++i) {
            var userId1 = game.gameSeats[i].userId;
            for (let j = i + 1; j < game.gameSeats.length; ++j) {
                var userId2 = game.gameSeats[j].userId;
                var type1 = card.getSpecialType(userId1);
                var type2 = card.getSpecialType(userId2);
                winScore = 0;
                if (type1 > type2) {
                    winScore = calSpecialTypeScore(type1, 1);
                } else if (type1 < type2) {
                    winScore = calSpecialTypeScore(type2, -1);
                }
                userScore[userId1] += winScore;
                userScore[userId2] -= winScore;
            }
            if (game.conf.zhuangMode == 1) {
                break;
            }
        }
    }
    for (let userId in userScore) {
        let userTmpId = Number.parseInt(userId);
        for (let j = 0; j < game.gameSeats.length; ++j) {
            let userId2 = game.gameSeats[j].userId;
            if (userTmpId == userId2) {
                console.log("game over score 1 ", game.gameSeats[j].score);
                userScore[userTmpId] = (userScore[userTmpId] == null) ? 0 : userScore[userTmpId];
                game.gameSeats[j].score = (game.gameSeats[j].score == null) ? 0 : game.gameSeats[j].score;
                game.gameSeats[j].score += userScore[userTmpId];
                console.log("game over score 2 ", game.gameSeats[j].score);
                calScoreByDaiMa(userTmpId);
                console.log("game over score 3 ", game.gameSeats[j].score);
                seats[j].score += game.gameSeats[j].score;
                console.log("game over total score ", seats[j].score);
                break;
            }
        }
    }

    console.log("play_out_push ", userPlayResult, userScore);
    userMgr.broadcastInRoom('play_out_push', { userDetail: userPlayResult, userScore: userScore }, userId, true);

    //如果局数慢，则结束房间
    var totalRes = getTotalScore(game, roomInfo, false);

    //保存每局结果
    // for (var key in userPlayResult) {
    //     for (let i = 0; i < userPlayResult[key].length; ++i) {
    //         if (userPlayResult[key][i] == null) {
    //             continue;
    //         }
    //         console.log("play_out_push user detail ", key, userPlayResult[key][i].channel, userPlayResult[key][i].pai);
    //     }
    // }

    //结束
    doGameOver(game, userId, 0, totalRes);
}

function getTotalScore(game, roomInfo, force) {
    var totalResult = {};
    if ((game != null && roomInfo.numOfGames == game.conf.maxGames) || force == true) {
        for (let k = 0; k < roomInfo.seats.length; ++k) {
            let userTmpId = roomInfo.seats[k].userId;
            totalResult[userTmpId] = { score: roomInfo.seats[k].score, name: roomInfo.seats[k].name };
        }
    }
    return totalResult;
}

function calSpecialTypeScore(type, winOrLose) {
    if (type == cn.resType.QINGLONG) {
        return winOrLose * 108;
    } else if (type == cn.resType.YITIAOLONG) {
        return winOrLose * 26;
    } else if (type == cn.resType.SANTONGHUASHUN) {
        return winOrLose * 18;
    } else if (type == cn.resType.SANFENTIANXIA) {
        return winOrLose * 16;
    } else if (type == cn.resType.SITAOSANTIAO) {
        return winOrLose * 8;
    } else if (type == cn.resType.LIUDUIBAN) {
        return winOrLose * 4;
    } else if (type == cn.resType.SANSHUNZI) {
        return winOrLose * 4;
    } else if (type == cn.resType.SANTONGHUA) {
        return winOrLose * 4;
    } else {
        return 0;
    }
}

function setSanShunzi(userId) {
    var channelDataTmp = channel.getChannelData(userId, 0);
    if (card.isShunZi(channelDataTmp)) {
        card.setSpecialType(userId, cn.resType.SANSHUNZI);
    }
}

function setSanTongHuaShun(userId) {
    var channelDataTmp = channel.getChannelData(userId, 0);
    if (channelDataTmp == null || channelDataTmp.pai == null || channelDataTmp.pai.length < 3) {
        return;
    }
    if ((channelDataTmp.pai[0] == channelDataTmp.pai[1] - 1 && channelDataTmp.pai[1] == channelDataTmp.pai[2] - 1)
        && card.isTongHua(channelDataTmp.pai)) {
        card.setSpecialType(userId, cn.resType.SANTONGHUASHUN);
    }
}

function addScorePerChannel(userPlayResult, userData1, userData2, userId1, userId2, k, res) {
    if (userPlayResult[userId1] === undefined) {
        userPlayResult[userId1] = [];
    }
    if (userPlayResult[userId2] === undefined) {
        userPlayResult[userId2] = [];
    }
    addScore(userPlayResult, userData1, userData2, userId1, userId2, k, res);
}

function addScore(userPlayResult, userData1, userData2, userId1, userId2, k, res) {
    let channelData = userPlayResult[userId1][k];
    if (channelData == null) {
        userPlayResult[userId1].push({
            type: userData1.type,
            channel: userData1.channel,
            pai: userData1.pai,
            score: res
        });
        //console.log("userPlayResult[userId1] ",userId1, userData1.pai);
    } else if (channelData.channel == k) {
        channelData.score += res;
    }
    channelData = userPlayResult[userId2][k];
    if (channelData == null) {
        userPlayResult[userId2].push({
            type: userData2.type,
            channel: userData2.channel,
            pai: userData2.pai,
            score: -1 * res
        });
        //console.log("userPlayResult[userId2] ",userId2, userData2.pai);
    } else if (channelData.channel == k) {
        channelData.score += res;
    }
}

function subScore(userPlayResult, userId, score) {
    for (var userIdKey in userPlayResult) {
        var tmpUserId = Number.parseInt(userIdKey);
        if (tmpUserId == null || tmpUserId == userId) {
            continue;
        }
        userPlayResult[tmpUserId].score -= score;
    }
}

function calScoreByDaiMa(userId) {
    var seatData = gameSeatsOfUsers[userId];
    if (seatData == null || seatData.game == null || !isDaiMa(seatData)) {
        return;
    }
    if (seatData != null && seatData.game != null) {
        var game = seatData.game;
        if (game.conf.maiMa == 1) {
            for (var i = 0; i < game.gameSeats.length; ++i) {
                var userTmpId = game.gameSeats[i];
                if (userTmpId == userId) {
                    continue;
                }
                seatData.score += (game.gameSeats[i].score * 2);
                game.gameSeats[i].score -= (game.gameSeats[i].score * 2);
            }
        }
    }
}

function isDaiMa(seatData) {
    if (seatData.holds != null) {
        if (seatData.holds.indexOf(cn.daiMa[0]) != -1) {
            return true;
        }
    }
    return false;
}

function update() {
    for (var i = dissolvingList.length - 1; i >= 0; --i) {
        var roomId = dissolvingList[i];
        var roomInfo = roomMgr.getRoom(roomId);
        if (roomInfo != null && roomInfo.dr != null && roomInfo.dr.endTime != null) {
            if (roomInfo.dr.endTime > 0 && roomInfo.dr.endTime < Date.now()) {
                dissolvingList.splice(i, 1);
                log.debug("request to delete room success ", dissolvingList, roomId);
                exports.doDissolve(roomId);
            }
        } else {
            log.debug("request to delete room failed ", dissolvingList, roomId);
            dissolvingList.splice(i, 1);
        }
    }

    for (var key in roomRes) {
        if (roomRes[key] != null && (roomRes[key].isSend || Date.now() - roomRes[key].saveTime > 30000)) {
            console.log("will delete room info key roomRes ", key, roomRes[key]);
            delete roomRes[key];
            break;
        }
    }
}

function onAutoPlayOut() {
    for (var key in games) {
        var roomId = Number.parseInt(key);
        if (roomId == null) {
            continue;
        }
        var game = games[roomId];
        if (game == null) {
            continue;
        }
        for (var i = 0; i < game.gameSeats.length; ++i) {
            var seatData = game.gameSeats[i];
            if (seatData == null || seatData.holds == null) {
                continue;
            }
            if (!seatData.isSubmit && Date.now() - seatData.beginTime > 300000) {
                for (var j = cn.channelNO.BOTTON; j >= cn.channelNO.HEAD; --j) {
                    var holdTmp = null;
                    if (j == cn.channelNO.BOTTON) {
                        holdTmp = [].concat(seatData.holds);
                    }
                    let lestType = card.calCardRes(seatData.userId, holdTmp);
                    if (lestType == null || lestType.length <= 0) {
                        continue;
                    }
                    let selPais = card.getUserCardInfo(seatData.userId, lestType[0]);
                    if (selPais == null || selPais.length <= 0) {
                        continue;
                    }
                    channel.setChannelData(seatData.userId, j, lestType[0], selPais);
                }
                exports.playOut(seatData.userId, 1);
            }
        }
    }
}

setInterval(onAutoPlayOut, 5000);
setInterval(update, 1000);
